package cn.net.xyan.yypt.service

import cn.net.xyan.blossom.core.service.ConfigService
import cn.net.xyan.blossom.core.utils.absoluteURL
import cn.net.xyan.blossom.core.utils.httpServletRequest
import cn.net.xyan.blossom.kotlin.*
import cn.net.xyan.yypt.dao.PayOrderDao
import cn.net.xyan.yypt.dao.PayRecordDao
import cn.net.xyan.yypt.dto.*
import cn.net.xyan.yypt.dto.protal.*
import cn.net.xyan.yypt.entity.PayOrder
import cn.net.xyan.yypt.entity.PayRecord
import com.fasterxml.jackson.dataformat.xml.XmlMapper
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.transaction.annotation.Transactional
import java.math.BigDecimal
import java.util.*
import javax.annotation.PostConstruct

const val KeyDefaultCallbackURL = "KeyDefaultCallbackURL"


@javax.jws.WebService(serviceName = "PayOrderService",
        portName = "PayOrderPort",
        targetNamespace = "http://www.yueyangyy.com/",
        endpointInterface = "cn.net.xyan.yypt.service.PayOrderService")
@AllOpen
class PayOrderServiceImpl : PayOrderService {



    companion object {
        const val KeyCallbackURL = "KeyCallbackURL"
        const val OrderTypeLinkingCloud = "LinkingCloud"
    }


    @Autowired
    lateinit var linkingCloudOpenApi: LinkingCloudOpenApi

    @Autowired
    lateinit var configService: ConfigService

    @Autowired
    lateinit var payOrderDao: PayOrderDao

    @Autowired
    lateinit var recordDao:PayRecordDao

    @Autowired
    lateinit var callback: PayOrderCallbackService

    @PostConstruct
    fun setup() {
        configService.setupVariable(KeyCallbackURL
                , "http://218.80.1.144:18002/ydpt/public/callback/linkingCloud"
                , "支付回调接口")
    }


    fun createPayRecord(payOrder: PayOrder?,fee:BigDecimal?,rawData:String?):PayRecord{
        var record = PayRecord()

        record.order = payOrder

        record.tradeFee = fee?:record.tradeFee

        record.rawData = rawData

        record.payVendor = payOrder?.payVendor
        record.payVendorNo = payOrder?.payVendorNo

        return recordDao.saveAndFlush(record)
    }

    override fun createLinkingCloudPayOrder(req: String): String {
        val mapper = XmlMapper()

        val callbackURL = configService.queryValue(PayOrderServiceImpl.KeyCallbackURL)

        val createReq: CreatePolymerizationQRCodeReq? = mapper.readValue(req, CreatePolymerizationQRCodeReq::class.javaType)

        createReq?.notifyURL = createReq?.notifyURL?:callbackURL

        var uuid = UUID.randomUUID()

        var payOrder = PayOrder(createReq?.outTradeNo?:uuid.toString(), createReq?.subject!!)


        payOrder.tradeFee = createReq.totalAmount!!
        payOrder.totalFee = payOrder.tradeFee
        payOrder.status = 1

        payOrder.type = OrderTypeLinkingCloud

        payOrder = payOrderDao.save(payOrder)


        var linkingCloudReq = CreatePolymerizationQRCodeReq()

        linkingCloudReq.outTradeNo = payOrder.orderID

        linkingCloudReq.totalAmount = payOrder.tradeFee

        linkingCloudReq.subject = payOrder.subject

        linkingCloudReq.notifyURL = callbackURL

        val rsp = linkingCloudOpenApi.createPolymerizationQRCodeOrder(linkingCloudReq)


        payOrder.attach = rsp.bizContent?.qrCode
        payOrder.outTradeNo = payOrder.orderID!!

        payOrder = payOrderDao.save(payOrder)


        var url = absoluteURL("/public/orderQrCode/${payOrder.orderID}")

        return payOrder.orderID!!
    }

    @Transactional
    override fun createPayOrder(req: String): String {
        val mapper = XmlMapper()

        val callbackURL = configService.queryValue(KeyCallbackURL)

        val createReq: LKAlipayEmptyBodyReq<LKAlipayQRCode>? = mapper.readValue(req, LKAlipayEmptyBodyReq::class.parametricType(LKAlipayQRCode::class.javaType))


        var linkingCloudReq = CreatePolymerizationQRCodeReq()
        //var linkingCloudReq = CreateQRCodeOrderReq()

        val head = createReq?.head

        if (head is LKAlipayQRCode) {

            linkingCloudReq.outTradeNo = head.outTradeNo

            linkingCloudReq.totalAmount = BigDecimal(head.totalAmount)

            linkingCloudReq.subject = head.caption

            linkingCloudReq.notifyURL = callbackURL

            //linkingCloudReq.paymentType = "alipay"

            val rsp = linkingCloudOpenApi.createPolymerizationQRCodeOrder(linkingCloudReq)
            //val rsp = linkingCloudOpenApi.createQRCodeOrder(linkingCloudReq)

            if (rsp?.bizContent?.qrCode != null) {
                val payOrder = PayOrder(head.outTradeNo!!, head.caption!!)
                //payOrder.orderID = head.outTradeNo!!
                payOrder.tradeFee = linkingCloudReq.totalAmount!!
                payOrder.totalFee = payOrder.tradeFee
                payOrder.status = 1
               // payOrder.payVendor = linkingCloudReq.paymentType
                payOrder.attach = rsp.bizContent?.qrCode
                payOrderDao.saveAndFlush(payOrder)
            }

            return mapper.writeValueAsString(rsp.toRsp())
        } else {
            throw StatusAndMessageError("请求格式不正确")
        }


    }


    override fun barcode(req: String): String {
        val mapper = XmlMapper()
        val createReq: LKAlipayEmptyBodyReq<LKBarcode>? = mapper.readValue(req, LKAlipayEmptyBodyReq::class.parametricType(LKBarcode::class.javaType))

        val linkingReq = CreateBarCodeOrderReq()

        val head = createReq?.head

        if (head is LKBarcode) {
            linkingReq.outTradeNo = head.outTradeNo
            linkingReq.authCode = head.authCode
            linkingReq.operatorID = head.operatorId
            linkingReq.terminalID = head.terminalId
            linkingReq.paymentType = head.paymentType
            linkingReq.totalAmount = BigDecimal(head.totalAmount)
        }

        val rsp = linkingCloudOpenApi.createBarCodeOrder(linkingReq)

        var status = rsp?.bizContent?.tradeStatus

        var reTry = 0
        while(status != TradeSuccess){
            if (status == WaitBuyerPay){
                Thread.sleep(1000*5)
                var linkingCloudQueryReq = QueryOrderReq()
                linkingCloudQueryReq.outTradeNo = linkingReq.outTradeNo
                val rsp = linkingCloudOpenApi.queryOrder(linkingCloudQueryReq)

                status = rsp?.bizContent?.tradeStatus

                reTry++

                if (reTry>3 ) break
            }
            else{
                throw StatusAndMessageError("交易失败:${rsp?.bizContent?.subMsg}")
            }
        }

        if (status == TradeSuccess){
            return mapper.writeValueAsString(rsp.toRsp())
        }else{
            throw StatusAndMessageError("交易失败")
        }

    }

    @Transactional
    override fun refund(req: String): String {
        val mapper = XmlMapper()
        val refundReq: LKAlipayEmptyBodyReq<LKAlipayRefund>? =
                mapper.readValue(req, LKAlipayEmptyBodyReq::class.parametricType(LKAlipayRefund::class.javaType))

        var linkingCloudReq = RefundOrderReq()

        val head = refundReq?.head

        if (head is LKAlipayRefund) {

            val payOrder = payOrderDao.findOne(head.tradeNo) ?:
                    throw StatusAndMessageError("订单${head.tradeNo}不存在 ")

            linkingCloudReq.outRequestNo = head.outRequestNo
            linkingCloudReq.outTradeNo = head.tradeNo
            linkingCloudReq.refundAmount = BigDecimal(head.refundAmount)
            linkingCloudReq.refundReason = head.refundmentReason

            linkingCloudReq.tradeAmount = payOrder.payFee

            linkingCloudReq.paymentType = payOrder.payVendor

            val rsp = linkingCloudOpenApi.refundOrder(linkingCloudReq)


            if (rsp.bizContent?.refundFee != null)
                println(rsp)

            payOrder.status = 7
            payOrder.refundDate = Date()

            payOrderDao.saveAndFlush(payOrder)



            createPayRecord(payOrder,  BigDecimal("-1") * BigDecimal(head.refundAmount) ,rsp.json)


            return mapper.writeValueAsString(rsp.toRsp())
        } else {
            throw StatusAndMessageError("请求格式不正确")
        }


    }

    override fun query(req: String): String {
        val mapper = XmlMapper()
        val queryReq: LKAlipayEmptyBodyReq<LKAlipayCheck>? =
                mapper.readValue(req, LKAlipayEmptyBodyReq::class.parametricType(LKAlipayCheck::class.javaType))

        var linkingCloudReq = QueryOrderReq()

        val head = queryReq?.head

        if (head is LKAlipayCheck) {

            linkingCloudReq.outTradeNo = head.outTradeNo
            linkingCloudReq.tradeNo = head.tradeNo


            val rsp = linkingCloudOpenApi.queryOrder(linkingCloudReq)
            return mapper.writeValueAsString(rsp.toRsp())
        } else {
            throw StatusAndMessageError("请求格式不正确")
        }

    }

    @Transactional
    fun onPay(notify: CallbackBizContentRsp) {
        var payOrder = payOrderDao.findByOutTradeNo(notify.outTradeNo)

        payOrder?.payVendorNo = notify.tradeNo
        payOrder?.payVendor = notify.payVendor
        payOrder?.status = 4

        payOrder?.payFee = notify.totalAmount ?: payOrder?.payFee?: BigDecimal("0")

        payOrderDao.saveAndFlush(payOrder)

        createPayRecord(payOrder,payOrder?.payFee,notify.json)

        if (notify?.tradeNo != null)
            try {
                callback.callback(notify)
            } catch (e: Throwable) {
                logger.error(e.stackTraceMessage)
            }
    }

}